#include "printscpthread.h"
//#include "global.h"

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */

BEGIN_EXTERN_C
#ifdef HAVE_FCNTL_H
#include <fcntl.h>       /* for O_RDONLY */
#endif
END_EXTERN_C

#include "dcmtk/ofstd/ofstream.h"
#include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */
#include "dcmtk/dcmpstat/dviface.h"
#include "dcmtk/ofstd/ofbmanip.h"       /* for OFBitmanipTemplate */
#include "dcmtk/dcmnet/diutil.h"
#include "dcmtk/dcmpstat/dvpsprt.h"

PrintScpThread::PrintScpThread(int port, QObject *parent) :
    _port(port),
    QThread(parent)
{
}

void PrintScpThread::run()
{
    emit threadStatus(LL_Info, tr("Listening association on port %1.").arg(_port));

#ifdef HAVE_WINSOCK_H
    WSAData winSockData;
    /* we need at least version 1.1 */
    WORD winSockVersionNeeded = MAKEWORD( 1, 1 );
    WSAStartup(winSockVersionNeeded, &winSockData);
#endif

    FILE *cfgfile = fopen(DCMPSTAT_CFG, "rb");
    if (cfgfile) fclose(cfgfile); else
    {
        emit threadStatus(LL_Error, tr("Can't open configuration file \"%1\".").arg(DCMPSTAT_CFG));
        return;
    }

    DVInterface dvi(DCMPSTAT_CFG);

    /* make sure data dictionary is loaded */
    if (!dcmDataDict.isDictionaryLoaded())
       emit threadStatus(LL_Warn, tr("no data dictionary loaded, check environment variable: %1.").arg(DCM_DICT_ENVIRONMENT_VARIABLE));

    /* check if we can get access to the database */
    const char *dbfolder = dvi.getDatabaseFolder();
    //emit threadStatus(PrintscpDialog::Info, tr("Using database in directory '%1'.").arg(dbfolder));

    OFCondition cond = EC_Normal;
    DcmQueryRetrieveIndexDatabaseHandle *dbhandle = new DcmQueryRetrieveIndexDatabaseHandle(dbfolder, PSTAT_MAXSTUDYCOUNT, PSTAT_STUDYSIZE, cond);
    delete dbhandle;
    if (cond.bad())
    {
      emit threadStatus(LL_Error, tr("Unable to access database: \"%1\".").arg(dbfolder));
      return;
    }

    T_ASC_Network *net = NULL; /* the DICOM network and listen port */

    /* open listen socket */
    cond = ASC_initializeNetwork(NET_ACCEPTOR, _port, 30, &net);
    if (cond.bad())
    {
      OFString temp_str;
      DimseCondition::dump(temp_str, cond);
      emit threadStatus(LL_Error, tr("Cannot initialise network: %1").arg(temp_str.c_str()));
    } else {
        OFBool finished = OFFalse;
        while (!finished)
        {
          DVPSPrintSCP printSCP(dvi, dvi.getTargetID(0, DVPSE_printAny)); // use new print SCP object for each association

          int connected = 0;
          while (!connected)
          {
             connected = ASC_associationWaiting(net, 1000);
          }
          setTerminationEnabled(false);
          switch (printSCP.negotiateAssociation(*net))
          {
            case DVPSJ_error:
              // association has already been deleted, we just wait for the next client to connect.
              break;
            case DVPSJ_terminate:
              finished=OFTrue;
              cond = ASC_dropNetwork(&net);
              break;
            case DVPSJ_success:
              QString calledAE = printSCP.getAssoc()->params->DULparams.calledAPTitle;
              emit threadStatus(LL_Info, tr("Association received, %1: %2 -> %3.")
                                .arg(printSCP.getAssoc()->params->DULparams.callingPresentationAddress)
                                .arg(printSCP.getAssoc()->params->DULparams.callingAPTitle)
                                .arg(calledAE));
              printSCP.handleClient();
              emit printJob(calledAE);
              break;
          }
          setTerminationEnabled(true);
        }
    }

#ifdef HAVE_WINSOCK_H
    WSACleanup();
#endif
}
